package com.main;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: Painter
 * @project_name: 五子棋
 * @time: 2022/7/28 19:37
 */


public class GamePanel extends JPanel implements ActionListener {
    public GameFrame gameFrame;
    public GamePanel panel;
    public static String gameFlag = "start";  // 游戏状态
    float x;  // 定义变量保存鼠标x坐标
    float y;  // 定义变量保存鼠标y坐标
    public boolean playerluozi = true;
    public boolean computerluozi = false;

    //    public Pointer[][] pointersList = new Pointer[15][15];  // 创建指示器类二位数组，15列，15行
    public List<Chess> chessList = new ArrayList<>();  // 存放已经落下的棋子
    public int[][] allChessList = new int[15][15];  // 定义一个二维数组，默认为0（没有落子）1白子，2黑子

    public GamePanel(GameFrame GFrame) {  // 定义一个参数，为主窗体对象，方便将面板内的组件添加到窗体中
        this.setLayout(null);  // 设置面板布局管理器为空，方便我们使用绝对坐标
        this.setOpaque(false);  // 有多少个组件绘制多少，显示背景,如果为 true，则组件绘制其边界内的每个像素。否则，组件可能不会绘制其部分或全部像素，从而允许底层像素显示出来。
        this.gameFrame = GFrame;  // 主窗体对象
        this.panel = this;
        createMenu();  // 调用方法创建菜单栏
        createMouseListener();  // 创建鼠标监听器
//        createPointer(); // 创建指示器对象
        ImagesValue.init(); // 加载图片
    }


    public Font createFont() {  // 创建字体
        return new Font("思源宋体", Font.BOLD, 18);
    }

    public void createMenu() {  // 创建菜单
        Font font = createFont();  // 创建字体

        JMenu jMenu1 = new JMenu("游戏");  // 创建游戏菜单
        JMenuItem jMenuItem1 = new JMenuItem("新游戏"); // 创建游戏菜单子菜单
        JMenuItem jMenuItem2 = new JMenuItem("退出"); // 创建游戏菜单子菜单
        jMenu1.add(jMenuItem1);  // 将子菜单添加到主菜单中
        jMenu1.add(jMenuItem2);  // 将子菜单添加到主菜单中
        jMenu1.setFont(font);  // 为菜单文字设置字体
        jMenuItem1.setFont(font);  // 为子菜单设置字体
        jMenuItem2.setFont(font);  // 为子菜单设置字体

        JMenu jMenu2 = new JMenu("帮助");  // 创建帮助菜单
        JMenuItem jMenuItem3 = new JMenuItem("操作说明"); // 创建帮助菜单子菜单
        JMenuItem jMenuItem4 = new JMenuItem("胜利条件"); // 创建帮助菜单子菜单
        jMenu2.add(jMenuItem3);  // 将子菜单添加到主菜单中
        jMenu2.add(jMenuItem4);  // 将子菜单添加到主菜单中
        jMenu2.setFont(font);  // 为菜单文字设置字体
        jMenuItem3.setFont(font);  // 为子菜单设置字体
        jMenuItem4.setFont(font);  // 为子菜单设置字体

        // 菜单栏对象
        JMenuBar jmb = new JMenuBar();  // 创建一个菜单栏对象
        jmb.add(jMenu1);  // 将菜单添加到菜单栏
        jmb.add(jMenu2);  // 将菜单添加到菜单栏

        gameFrame.setJMenuBar(jmb);  // 设置当前面板的菜单栏，并添加菜单栏

        // 添加监听事件
        jMenuItem1.addActionListener(this);
        jMenuItem2.addActionListener(this);
        jMenuItem3.addActionListener(this);
        jMenuItem4.addActionListener(this);
        // 绑定事件
        jMenuItem1.setActionCommand("restart");
        jMenuItem2.setActionCommand("exit");
        jMenuItem3.setActionCommand("manual");
        jMenuItem4.setActionCommand("rule");


    }

    public void createMouseListener() {
        MouseAdapter mouseAdapter = new MouseAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {  // 鼠标移动
                x = e.getX();  // 将鼠标的x坐标赋值给x
                y = e.getY();  // 将鼠标的y坐标赋值给y
            }

            @Override
            public void mousePressed(MouseEvent e) {  // 鼠标按下
                x = e.getX();  // 将鼠标的x坐标赋值给x
                y = e.getY();  // 将鼠标的y坐标赋值给y
                float x1 = (x - 20) / 40;   // 获取鼠标坐标在棋盘的坐标系数
                float y1 = (y - 20) / 40;

                int x3 = Math.round(x1);  // 棋盘网格的x坐标
                int y3 = Math.round(y1);  // 棋盘网格的y坐标

                int x2 = x3 * 40 + 20;  // 计算出鼠标的坐标距离棋盘坐标最近的棋子点位
                int y2 = y3 * 40 + 20;

                if ("start".equals(gameFlag)) {  // 如果游戏状态为开始状态
                    if (allChessList[x3][y3] == 0 && playerluozi) {  // 如果所有棋子数组中这个位置是0（没有棋子），就添加棋子
                        System.out.println("玩家落子");
                        System.out.println("(" + x3 + "," + y3 + ")");
                        Music.playMusic();
                        chessList.add(new Chess(x2 - 18, y2 - 18, 2));  // 向数组中添加一个黑棋对象
                        allChessList[x3][y3] = 2;
                        playerluozi = false;
                        clearalllast();
                        if (JudgingWin(2, x3, y3) == 2) {
                            gameFlag = "end";
                            System.out.println("玩家胜利");
                            JOptionPane.showMessageDialog(null,"恭喜你胜利了！");
                        } else {
                            computerluozi = true;
                            AI.luozi(1,panel);
                        }
                    }
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {  // 鼠标释放
//                System.out.println("鼠标释放");
            }
        };
        addMouseMotionListener(mouseAdapter);  // 添加鼠标运动监听器
        addMouseListener(mouseAdapter);  // 添加鼠标监听器
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String command = e.getActionCommand();  // 获取指令
        switch (command) {
            case "restart":
                allChessList = new int[15][15];
                chessList.removeAll(chessList);
                playerluozi = true;
                gameFlag = "start";
                break;
            case "exit":
                int num = JOptionPane.showConfirmDialog(null,"是否退出游戏");
                if (num==0) System.exit(0);
                break;
            case "manual":
                String str = "点击没有棋子的地方下棋。五子连珠胜利";  // 提示信息
                JOptionPane.showMessageDialog(null,str);
//                int val = JOptionPane.showConfirmDialog(null,"提示信息");  // 确认对话框
//                System.out.println(val);
//                String str1 = JOptionPane.showInputDialog(null,"提示信息");  // 输入框
//                System.out.println(str1);
                break;
            case "rule":
                JOptionPane.showMessageDialog(null,"五子在四个方向连珠");
                break;
        }
    }

    @Override
    public void paint(Graphics g) {
//        g.drawImage(ImagesValue.blackPawn, 0,0,30,30,null );
//        g.drawImage(ImagesValue.backgroundImg, 0, 0, this.getWidth(), this.getHeight(), null);
        drawGrid(g);  // 绘制棋盘
        drawPointer(g);  // 绘制指示器
        drawChess(g);
        repaint();  //  重新绘制
    }


    public void clearalllast() {
        for (Chess chess : chessList) {
            chess.last = false;
        }
    }

    public void drawGrid(Graphics g) {  // 绘制棋盘
        int grid = 40;  // 格子的宽和高

        g.setColor(new Color(0, 0, 0));  // 设置画笔为黑色

        for (int i = 0; i < 15; i++) {  // 绘制棋盘横线
            g.drawLine(20, i * grid + 20, grid * 15 - 20, i * grid + 20);
        }
        for (int i = 0; i < 15; i++) {  // 绘制棋盘纵线
            g.drawLine(i * grid + 20, 20, i * grid + 20, grid * 15 - 20);
        }
        // 绘制棋盘的黑圆点，填充圆弧
        g.fillArc(135, 135, 10, 10, 0, 360);
        g.fillArc(455, 135, 10, 10, 0, 360);
        g.fillArc(135, 455, 10, 10, 0, 360);
        g.fillArc(455, 455, 10, 10, 0, 360);
        g.fillArc(295, 295, 10, 10, 0, 360);

        Graphics2D g2d = (Graphics2D) g;
        g2d.setStroke(new BasicStroke(4));
        g2d.drawLine(14,14,584,14);
        g2d.drawLine(14,14,14,584);
        g2d.drawLine(586,14,586,584);
        g2d.drawLine(14,586,586,586);

    }


    public void drawPointer(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setStroke(new BasicStroke(2));
        g2d.setColor(new Color(255, 0, 0));
        float x1 = (x - 20) / 40;   // 获取鼠标坐标在棋盘的坐标系数
        float y1 = (y - 20) / 40;

        int x2 = Math.round(x1) * 40 + 20;  // 计算出鼠标的坐标距离棋盘坐标最近的棋子点位
        int y2 = Math.round(y1) * 40 + 20;

        int x3 = Math.round(x1);  // 棋盘网格的x坐标
        int y3 = Math.round(y1);  // 棋盘网格的y坐标

        if (allChessList[x3][y3] == 0) {
            if ("start".equals(gameFlag)) {  // 如果游戏状态为开始状态
                if (x > 20 && y > 20 && x < 580 && y < 580) {  // 如果鼠标在棋盘的坐标范围内
                    /**
                     * x = 鼠标的x坐标，y = 鼠标的y坐标
                     * x1 = 棋盘的x坐标，y1 = 棋盘的y坐标
                     */

                    if (x2 > 20 && y2 > 20) {  // 绘制左上角
                        g2d.drawLine(x2 - 20, y2 - 20, x2 - 10, y2 - 20);
                        g2d.drawLine(x2 - 20, y2 - 20, x2 - 20, y2 - 10);
                    }
                    if (x2 < 580 && y2 > 20) {  // 绘制右上角
                        g2d.drawLine(x2 + 20, y2 - 20, x2 + 10, y2 - 20);
                        g2d.drawLine(x2 + 20, y2 - 20, x2 + 20, y2 - 10);
                    }
                    if (x2 > 20 && y2 < 580) {  // 绘制左下角
                        g2d.drawLine(x2 - 20, y2 + 10, x2 - 20, y2 + 20);
                        g2d.drawLine(x2 - 20, y2 + 20, x2 - 10, y2 + 20);
                    }
                    if (x2 < 580 && y2 < 580) {  // 绘制右下角
                        g2d.drawLine(x2 + 10, y2 + 20, x2 + 20, y2 + 20);
                        g2d.drawLine(x2 + 20, y2 + 10, x2 + 20, y2 + 20);
                    }
                }
            }
//        repaint();  // 重新绘制
        }
    }

    public void drawChess(Graphics g) {  // 绘制落下棋子
        for (Chess chess : chessList) {  // 遍历棋子数组
            chess.draw(g);  // 调用draw方法绘制棋子
        }
    }


    public int JudgingWin(int type, int x , int y) {
        int BCount = 1;
        int[][] note = allChessList;
        // 水平查找
        boolean Lbol = true;// 默认向左走可以获胜
        boolean Rbol = true;// 默认向右走可以获胜
        for (int i = 1; i <= 5; i++) {// 以参数棋子为原点，向在水平方向走出5步
            if ((y + i) > 14) {// 如果棋子超出最大列数
                Rbol = false;// 向右走不会获胜
            }
            if ((y - i) < 0) {// 如果棋子超出最小列数
                Lbol = false;// 向左走不会获胜
            }
            if (Rbol) {// 如果向右走可能会获胜
                // 如果向右走，挨着我的棋子都与我颜色相同
                if (note[x][y + i] == type) {
                    ++BCount;// 连子数递增
                } else {
                    Rbol = false;// 向右走不会获胜
                }
            }
            if (Lbol) {// 如果向左走可能会获胜
                // 如果向左走，挨着我的棋子都与我颜色相同
                if (note[x][y - i] == type) {
                    ++BCount;// 连子数递增
                } else {
                    Lbol = false;// 向左走不会获胜
                }
            }
            if (BCount >= 5) {// 如果同类型的棋子数大于等于5个
                return type; // 返回胜利一方的棋子的值
            }
        }

        // 垂直查找
        boolean Ubol = true;// 默认向上走可以获胜
        boolean Dbol = true;// 默认向下走可以获胜
        BCount = 1;// 连子个数初始化
        for (int i = 1; i <= 5; i++) {// 以参数棋子为原点，向在垂直方向走出5步
            if ((x + i) > 14) {// 如果超出棋盘的最大行数
                Dbol = false;// 向下走不会获胜
            }
            if ((x - i) < 0) {// 如果超出棋盘的最小行数
                Ubol = false;// 向上走不会获胜
            }
            if (Dbol) {// 如果向下走可以获胜
                // 如果向下走，挨着我的棋子都与我颜色相同
                if (note[x + i][y] == type) {
                    ++BCount;// 连子数递增
                } else {
                    Dbol = false;// 向下走不会获胜
                }
            }
            if (Ubol) {// 如果向上走可能获胜
                // 如果向上走，挨着我的棋子都与我颜色相同
                if (note[x - i][y] == type) {
                    ++BCount;// 连子数递增
                } else {
                    Ubol = false;// 向上走不会获胜
                }
            }
            if (BCount >= 5) { // 如果同类型的棋子大于等于5个
                return type; // 返回胜利一方的棋子
            }
        }

        // 正斜查找
        boolean LUbol = true;// 默认向左上走可以获胜
        boolean RDbol = true;// 默认向右下走可以获胜
        BCount = 1;// 连子个数初始化
        for (int i = 1; i <= 5; i++) {// 以参数棋子为原点，向在正斜方向走出5步
            if ((x - i) < 0 || (y - i < 0)) {// 如果超出左上的斜线
                LUbol = false;// 向左上走不会获胜
            }
            if ((x + i) > 14 || (y + i > 14)) {// 如果超出右下的斜线
                RDbol = false;// 向右下走不会获胜
            }
            if (LUbol) {// 如果向左上走可以获胜
                // 如果向左上走，挨着我的棋子都与我颜色相同
                if (note[x - i][y - i] == type) {// 如果左上斜线上有相同类型的棋子
                    ++BCount;// 连子数递增
                } else {
                    LUbol = false;// 向左上走不会获胜
                }
            }
            if (RDbol) {// 如果向右下走可以获胜
                // 如果向右下走，挨着我的棋子都与我颜色相同
                if (note[x + i][y + i] == type) {// 如果右下斜线上有相同类型的棋子
                    ++BCount;// 连子数递增
                } else {
                    RDbol = false;// 向右下走不会获胜
                }
            }
            if (BCount >= 5) {// 如果同类型的棋子大于等于5个
                return type; // 返回胜利一方的棋子
            }
        }
        // 反斜查找
        boolean RUbol = true;// 默认向右上走可以获胜
        boolean LDbol = true;// 默认向左下走可以获胜
        BCount = 1;// 连子个数初始化
        for (int i = 1; i <= 5; i++) {// 以参数棋子为原点，向在反斜方向走出5步
            if ((x - i) < 0 || (y + i > 14)) {// 如果超出右上的斜线
                RUbol = false;// 向右上走不会获胜
            }
            if ((x + i) > 14 || (y - i < 0)) {// 如果超出左下的斜线
                LDbol = false;// 向左下走不会获胜
            }
            if (RUbol) {// 如果向右上走可以获胜
                // 如果向右上走，挨着我的棋子都与我颜色相同
                if (note[x - i][y + i] == type) {
                    ++BCount;// 连子数递增
                } else {
                    RUbol = false;// 默认向右上走可以获胜
                }
            }
            if (LDbol) {// 如果向左下走可以获胜
                // 如果向左下走，挨着我的棋子都与我颜色相同
                if (note[x + i][y - i] == type) {
                    ++BCount;// 连子数递增
                } else {
                    LDbol = false;// 默认向左下走可以获胜
                }
            }
            if (BCount >= 5) {// 如果同类型的棋子大于等于5个
                return type;// 返回胜利一方的棋子
            }
        }
        return 0;

    }

}
